/* @(#)FmmMediator.java
** 
** Copyright (C) 2012 by Steven D. Stamps
**
**             Trademarks & Copyrights
** Flywheel Management Science(TM), Flywheel Management Model(TM),
** Flywheel Story Editor(TM) and FlywheelMS(TM) are exclusive trademarks
** of Steven D. Stamps and may only be used freely for the purpose of
** identifying the unforked version of this software.  Subsequent forks
** may not use these trademarks.  All other rights are reserved.
** and FlywheelMS(TM) are exclusive trademarks of Steven D. Stamps
** and may only be used freely for the purpose of identifying the
** unforked version of this software.  Subsequent forks (if any) may
** not use these trademarks.  All other rights are reserved.
**
** DecKanGL (Decorated Kanban Glyph Language) and TribKn (Tribal Knowledge)
** are also exclusive trademarks of Steven D. Stamps.  These may be used
** freely within the unforked FlywheelMS application and documentation.
** All other rights are reserved.
**
** Trademark information is available at
** <http://www.flywheelms.com/trademarks>
**
** Flywheel Management Science(TM) is a copyrighted body of management
** metaphors, governance processes, and leadership techniques that is
** owned by Steven D. Stamps.  These copyrighted materials may be freely
** used, without alteration, by the community (users and developers)
** surrounding this GPL3-licensed software.  Additional copyright
** information is available at <http://www.flywheelms.org/copyrights>
**
**              GPL3 Software License
** This program is free software: you can use it, redistribute it and/or
** modify it under the terms of the GNU General Public License, version 3,
** as published by the Free Software Foundation. This program is distributed
** in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
** even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
** PURPOSE.  See the GNU General Public License for more details. You should
** have received a copy of the GNU General Public License, in a file named
** COPYING, along with this program.  If you cannot find your copy, see
** <http://www.gnu.org/licenses/gpl-3.0.html>.
*/

package com.flywheelms.library.fmm;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;

import com.flywheelms.library.fmm.database.FmmDatabaseMediatorMySql;
import com.flywheelms.library.fmm.database.FmmDatabaseMediatorSqLite;
import com.flywheelms.library.fmm.database.RepositoryConfiguration;
import com.flywheelms.library.fmm.helper.FmmHelper;
import com.flywheelms.library.fmm.node.FmmNodeInfo;
import com.flywheelms.library.fmm.node.impl.commitment.StrategicCommitment;
import com.flywheelms.library.fmm.node.impl.enumerator.FmmNodeDictionary;
import com.flywheelms.library.fmm.node.impl.governable.FiscalYear;
import com.flywheelms.library.fmm.node.impl.governable.FlywheelTeam;
import com.flywheelms.library.fmm.node.impl.governable.FmsOrganization;
import com.flywheelms.library.fmm.node.impl.governable.ProjectAsset;
import com.flywheelms.library.fmm.node.impl.governable.StrategicMilestone;
import com.flywheelms.library.fmm.node.impl.governable.WorkPackage;
import com.flywheelms.library.fmm.node.impl.headline.CommunityMember;
import com.flywheelms.library.fmm.node.impl.link.ProjectAssetLinkToWorkPackage;
import com.flywheelms.library.fmm.node.impl.nodefrag.NodeFragGovernance;
import com.flywheelms.library.fse.model.FseDocument;

/*
 * An instance of FmmDatabaseMediator is created for each configured Repository Service.
 * The fmmDatabaseMediatorMap data member is a container for all FmmDatabaseMediator instances,
 * indexed by the configuration of the database instance.
 */
public abstract class FmmDatabaseMediator {
	
	private static HashMap<String, FmmDatabaseMediator> fmmDatabaseMediatorMap = new HashMap<String, FmmDatabaseMediator>();  // mediator for each database server
	private static FmmDatabaseMediator activeFmmDatabaseMediator;
	
	protected RepositoryConfiguration repositoryConfiguration;
	private FmsOrganization activeOrganization;
	
	protected HashMap<String, CommunityMember> communityMemberMap;
	protected HashMap<String, FiscalYear> fiscalYearMap;
	protected HashMap<String, FlywheelTeam> flywheelTeamMap;
	protected HashMap<String, NodeFragGovernance> nodeFragGovernanceMap;
	protected HashMap<String, FmsOrganization> organizationMap;
	protected HashMap<String, ProjectAsset> projectAssetMap;
	protected HashMap<String, ProjectAssetLinkToWorkPackage> projectAssetLinkToWorkPackageMap;
	protected HashMap<String, StrategicCommitment> strategicCommitmentMap;
	protected HashMap<String, StrategicMilestone> strategicMilestoneMap;
	protected HashMap<String, WorkPackage> workPackageMap;
	protected final HashMap<String, FseDocument> fseDocumentMap = new HashMap<String, FseDocument>();
	
	protected FmmDatabaseMediator(RepositoryConfiguration aRepositoryConfiguration) {
		this.repositoryConfiguration = aRepositoryConfiguration;
		initializeCommunityMemberMap();
		initializeFiscalYearMap();
		initializeFlywheelTeamMap();
		initializeNodeFragGovernanceMap();
		initializeOrganizationMap();
		initializeProjectAssetMap();
		initializeProjectAssetLinkToWorkPackageMap();
		initializeStrategicCommitmentMap();
		initializeStrategicMilestoneMap();
		initializeWorkPackageMap();
		setInitialActiveOrganization();
	}
	
	private void setInitialActiveOrganization() {
		this.activeOrganization = (FmsOrganization) this.organizationMap.values().toArray()[0];
	}

	private static FmmDatabaseMediator getInstance(RepositoryConfiguration aRepositoryConfiguration) {
		FmmDatabaseMediator theFmmMediator = FmmDatabaseMediator.fmmDatabaseMediatorMap.get(aRepositoryConfiguration.getName());
		if(theFmmMediator == null) {
			theFmmMediator = createFmmMediator(aRepositoryConfiguration);
			FmmDatabaseMediator.fmmDatabaseMediatorMap.put(aRepositoryConfiguration.getName(),theFmmMediator);
		}
		return FmmDatabaseMediator.fmmDatabaseMediatorMap.get(aRepositoryConfiguration.getName());
	}

	public static FmmDatabaseMediator getInstanceAndSetActive(RepositoryConfiguration aRepositoryConfiguration) {
		FmmDatabaseMediator.activeFmmDatabaseMediator = getInstance(aRepositoryConfiguration);
		return FmmDatabaseMediator.activeFmmDatabaseMediator;
	}

	public static void setActiveMediator(RepositoryConfiguration aRepositoryConfiguration) {
		FmmDatabaseMediator.activeFmmDatabaseMediator = getInstance(aRepositoryConfiguration);
	}
	
	public static FmmDatabaseMediator getActiveMediator() {
		if(FmmDatabaseMediator.activeFmmDatabaseMediator == null) {
			setActiveMediator(FmmHelper.getLocalRepositoryConfiguration());
		}
		return FmmDatabaseMediator.activeFmmDatabaseMediator;
	}

	public FmsOrganization getActiveOrganization() {
		return this.activeOrganization;
	}
	
	public void setActiveOrganization(FmsOrganization anOrganization) {
		this.activeOrganization = anOrganization;
	}

	private static FmmDatabaseMediator createFmmMediator(RepositoryConfiguration aRepositoryConfiguration) {
		switch (aRepositoryConfiguration.getDatabaseTechnology()) {
		  case SQLITE:
			  return new FmmDatabaseMediatorSqLite(aRepositoryConfiguration);
		  case MYSQL:
			  return new FmmDatabaseMediatorMySql(aRepositoryConfiguration);
		  default:
			  return null;
		}
	}

	public RepositoryConfiguration getRepositoryConfiguration() {
		return this.repositoryConfiguration;
	}

	//////  Node - COMMUNITY MEMBER  ////////////////////////////////////////////////////////////////////////////////

	protected int initializeCommunityMemberMap() {
		ArrayList<CommunityMember> theCommunityMemberList = dbRetrieveCommunityMemberList();
		this.communityMemberMap = new HashMap<String, CommunityMember>();
		for(CommunityMember theCommunityMember : theCommunityMemberList) {
			this.communityMemberMap.put(theCommunityMember.getNodeIdString(), theCommunityMember);
		}
		return this.communityMemberMap.size();
	}
	
	public Collection<CommunityMember> getCommunityMemberCollection() {
		return this.communityMemberMap.values();
	}
	
//	public Collection<CommunityMember> getCommunityMemberCollection(Organization anOrganization) {
//		ArrayList<CommunityMember> theCommunityMemberList = new ArrayList<CommunityMember>();
//		for(CommunityMember theCommunityMember : this.communityMemberMap.values()) {
//			if(theCommunityMember.isMemberOfOrganization(anOrganization.getNodeIdString())) {
//				theCommunityMemberList.add(theCommunityMember);
//			}
//		}
//		return theCommunityMemberList;
//	}
	
//	@SuppressWarnings("unchecked")
//	public Collection<CommunityMember> getCommunityMemberCollectionSorted(Organization anOrganization) {
//		Collection<CommunityMember> theCommunityMemberList = getCommunityMemberCollection(anOrganization);
//		Collections.sort((ArrayList<CommunityMember>)theCommunityMemberList);
//		return theCommunityMemberList;
//	}
	
	public CommunityMember getCommunityMember(String aNodeIdString) {
		CommunityMember theCommunityMember = this.communityMemberMap.get(aNodeIdString);
		if(theCommunityMember == null) {
			theCommunityMember = dbRetrieveCommunityMember(aNodeIdString);
			if(theCommunityMember != null) {
				this.communityMemberMap.put(theCommunityMember.getNodeIdString(), theCommunityMember);
			}
		}
		return theCommunityMember;
	}
	
	public void newCommunityMember(CommunityMember aCommunityMember) {
		dbInsertCommunityMember(aCommunityMember);
		this.communityMemberMap.put(aCommunityMember.getNodeIdString(), aCommunityMember);
	}

	public void destroyCommunityMember(CommunityMember aCommunityMember) {
		dbDeleteCommunityMember(aCommunityMember);
		this.communityMemberMap.remove(aCommunityMember.getNodeIdString());
	}
	
			////  Repository Access - COMMUNITY MEMBER

	protected abstract ArrayList<CommunityMember> dbRetrieveCommunityMemberList();

	protected abstract ArrayList<CommunityMember> dbRetrieveCommunityMemberList(FmsOrganization anOrganization);
	
	protected abstract CommunityMember dbRetrieveCommunityMember(String aNodeIdString);
	
	protected abstract void dbInsertCommunityMember(CommunityMember aCommunityMember);
	
	public abstract void dbDeleteCommunityMember(CommunityMember aCommunityMember);

	//////  Node - FISCAL YEAR  ////////////////////////////////////////////////////////////////////////////////

	protected int initializeFiscalYearMap() {
		ArrayList<FiscalYear> theFiscalYearList = dbRetrieveFiscalYearList();
		this.fiscalYearMap = new HashMap<String, FiscalYear>();
		for(FiscalYear theFiscalYear : theFiscalYearList) {
			this.fiscalYearMap.put(theFiscalYear.getNodeIdString(), theFiscalYear);
		}
		return this.fiscalYearMap.size();
	}
	
	public Collection<FiscalYear> getFiscalYearCollection() {
		return this.fiscalYearMap.values();
	}
	
	public Collection<FiscalYear> getFiscalYearCollection(FmsOrganization anOrganization) {
		ArrayList<FiscalYear> theFiscalYearList = new ArrayList<FiscalYear>();
		for(FiscalYear theFiscalYear : this.fiscalYearMap.values()) {
			if(theFiscalYear.getOrganizationNodeId().equals(anOrganization.getNodeIdString())) {
				theFiscalYearList.add(theFiscalYear);
			}
		}
		return theFiscalYearList;
	}
	
	public Collection<FiscalYear> getFiscalYearCollectionSorted(FmsOrganization anOrganization) {
		Collection<FiscalYear> theFiscalYearList = getFiscalYearCollection(anOrganization);
		Collections.sort((ArrayList<FiscalYear>)theFiscalYearList);
		return theFiscalYearList;
	}
	
	public FiscalYear getFiscalYear(String aNodeIdString) {
		FiscalYear theFiscalYear = this.fiscalYearMap.get(aNodeIdString);
		if(theFiscalYear == null) {
			theFiscalYear = dbRetrieveFiscalYear(aNodeIdString);
			if(theFiscalYear != null) {
				this.fiscalYearMap.put(theFiscalYear.getNodeIdString(), theFiscalYear);
			}
		}
		return theFiscalYear;
	}
	
	public void newFiscalYear(FiscalYear aFiscalYear) {
		dbInsertFiscalYear(aFiscalYear);
		this.fiscalYearMap.put(aFiscalYear.getNodeIdString(), aFiscalYear);
	}

	public void destroyFiscalYear(FiscalYear aFiscalYear) {
		dbDeleteFiscalYear(aFiscalYear);
		this.fiscalYearMap.remove(aFiscalYear.getNodeIdString());
	}
	
			////  Repository Access - FISCAL YEAR

	protected abstract ArrayList<FiscalYear> dbRetrieveFiscalYearList();

	protected abstract ArrayList<FiscalYear> dbRetrieveFiscalYearList(FmsOrganization anOrganization);
	
	protected abstract FiscalYear dbRetrieveFiscalYear(String aNodeIdString);
	
	protected abstract void dbInsertFiscalYear(FiscalYear aFiscalYear);
	
	public abstract void dbDeleteFiscalYear(FiscalYear aFiscalYear);

	//////  Node - FLYWHEEL TEAM  ////////////////////////////////////////////////////////////////////////////////

	protected int initializeFlywheelTeamMap() {
		ArrayList<FlywheelTeam> theFlywheelTeamList = dbRetrieveFlywheelTeamList();
		this.flywheelTeamMap = new HashMap<String, FlywheelTeam>();
		for(FlywheelTeam theFlywheelTeam : theFlywheelTeamList) {
			this.flywheelTeamMap.put(theFlywheelTeam.getNodeIdString(), theFlywheelTeam);
		}
		return this.flywheelTeamMap.size();
	}
	
	public Collection<FlywheelTeam> getFlywheelTeamCollection() {
		return this.flywheelTeamMap.values();
	}
	
	public ArrayList<FlywheelTeam> getFlywheelTeamList(String anOrganizationNodeId) {
		ArrayList<FlywheelTeam> theFlywheelTeamList = new ArrayList<FlywheelTeam>();
		for(FlywheelTeam theFlywheelTeam : this.flywheelTeamMap.values()) {
			if(theFlywheelTeam.getOrganizationNodeId().equals(anOrganizationNodeId)) {
				theFlywheelTeamList.add(theFlywheelTeam);
			}
		}
		return theFlywheelTeamList;
	}
	
	public Collection<FlywheelTeam> getFlywheelTeamCollection(FmsOrganization anOrganization) {
		return getFlywheelTeamList(anOrganization.getNodeIdString());
	}
	
	public FlywheelTeam getFlywheelTeam(String aNodeIdString) {
		FlywheelTeam theFlywheelTeam = this.flywheelTeamMap.get(aNodeIdString);
		if(theFlywheelTeam == null) {
			theFlywheelTeam = dbRetrieveFlywheelTeam(aNodeIdString);
			if(theFlywheelTeam != null) {
				this.flywheelTeamMap.put(theFlywheelTeam.getNodeIdString(), theFlywheelTeam);
			}
		}
		return theFlywheelTeam;
	}
	
	public void newFlywheelTeam(FlywheelTeam aFlywheelTeam) {
		dbInsertFlywheelTeam(aFlywheelTeam);
		this.flywheelTeamMap.put(aFlywheelTeam.getNodeIdString(), aFlywheelTeam);
	}

	public void destroyFlywheelTeam(FlywheelTeam aFlywheelTeam) {
		dbDeleteFlywheelTeam(aFlywheelTeam);
		this.flywheelTeamMap.remove(aFlywheelTeam.getNodeIdString());
	}
	
			////  Repository Access - FLYWHEEL TEAM

	protected abstract ArrayList<FlywheelTeam> dbRetrieveFlywheelTeamList();

	protected abstract ArrayList<FlywheelTeam> dbRetrieveFlywheelTeamList(FmsOrganization anOrganization);
	
	protected abstract FlywheelTeam dbRetrieveFlywheelTeam(String aNodeIdString);
	
	protected abstract void dbInsertFlywheelTeam(FlywheelTeam aFlywheelTeam);
	
	public abstract void dbDeleteFlywheelTeam(FlywheelTeam aFlywheelTeam);
	
	
	//////  Node - NODE_FRAG_GOVERNANCE  ////////////////////////////////////////////////////////////////////////////////

	protected int initializeNodeFragGovernanceMap() {
		ArrayList<NodeFragGovernance> theNodeFragGovernanceList = dbRetrieveNodeFragGovernanceList();
		this.nodeFragGovernanceMap = new HashMap<String, NodeFragGovernance>();
		for(NodeFragGovernance theNodeFragGovernance : theNodeFragGovernanceList) {
			this.nodeFragGovernanceMap.put(theNodeFragGovernance.getNodeIdString(), theNodeFragGovernance);
		}
		return this.nodeFragGovernanceMap.size();
	}
	
	public Collection<NodeFragGovernance> getNodeFragGovernanceCollection() {
		return this.nodeFragGovernanceMap.values();
	}
	
	public NodeFragGovernance getNodeFragGovernance(String aNodeIdString) {
		NodeFragGovernance theNodeFragGovernance = this.nodeFragGovernanceMap.get(aNodeIdString);
		if(theNodeFragGovernance == null) {
			theNodeFragGovernance = dbRetrieveNodeFragGovernance(aNodeIdString);
			if(theNodeFragGovernance != null) {
				this.nodeFragGovernanceMap.put(theNodeFragGovernance.getNodeIdString(), theNodeFragGovernance);
			}
		}
		return theNodeFragGovernance;
	}
	
	public void newNodeFragGovernance(NodeFragGovernance aNodeFragGovernance) {
		dbInsertNodeFragGovernance(aNodeFragGovernance);
		this.nodeFragGovernanceMap.put(aNodeFragGovernance.getNodeIdString(), aNodeFragGovernance);
	}

	public void destroyNodeFragGovernance(NodeFragGovernance aNodeFragGovernance) {
		dbDeleteNodeFragGovernance(aNodeFragGovernance);
		this.nodeFragGovernanceMap.remove(aNodeFragGovernance.getNodeIdString());
	}
	
			////  Repository Access - NODE FRAG GOVERNANCE

	protected abstract ArrayList<NodeFragGovernance> dbRetrieveNodeFragGovernanceList();

	protected abstract NodeFragGovernance dbRetrieveNodeFragGovernance(String aNodeIdString);
	
	protected abstract void dbInsertNodeFragGovernance(NodeFragGovernance aNodeFragGovernance);
	
	public abstract void dbDeleteNodeFragGovernance(NodeFragGovernance aNodeFragGovernance);
	
	
	//////  Node - ORGANIZATION  ////////////////////////////////////////////////////////////////////////////////

	protected int initializeOrganizationMap() {
		ArrayList<FmsOrganization> theOrganizationList = dbRetrieveOrganizationList();
		this.organizationMap = new HashMap<String, FmsOrganization>();
		for(FmsOrganization theOrganization : theOrganizationList) {
			this.organizationMap.put(theOrganization.getNodeIdString(), theOrganization);
		}
		return this.organizationMap.size();
	}
	
	public Collection<FmsOrganization> getOrganizationCollection() {
		return this.organizationMap.values();
	}
	
	public FmsOrganization getOrganization(String aNodeIdString) {
		FmsOrganization theOrganization = this.organizationMap.get(aNodeIdString);
		if(theOrganization == null) {
			theOrganization = dbRetrieveOrganization(aNodeIdString);
			if(theOrganization != null) {
				this.organizationMap.put(theOrganization.getNodeIdString(), theOrganization);
			}
		}
		return theOrganization;
	}
	
	public void newOrganization(FmsOrganization aOrganization) {
		dbInsertOrganization(aOrganization);
		this.organizationMap.put(aOrganization.getNodeIdString(), aOrganization);
	}

	public void destroyOrganization(FmsOrganization aOrganization) {
		dbDeleteOrganization(aOrganization);
		this.organizationMap.remove(aOrganization.getNodeIdString());
	}
	
			////  Repository Access - ORGANIZATION

	protected abstract ArrayList<FmsOrganization> dbRetrieveOrganizationList();
	
	protected abstract FmsOrganization dbRetrieveOrganization(String aNodeIdString);
	
	protected abstract void dbInsertOrganization(FmsOrganization aOrganization);
	
	public abstract void dbDeleteOrganization(FmsOrganization aOrganization);

	//////  Node - PROJECT ASSET  ////////////////////////////////////////////////////////////////////////////////

	protected int initializeProjectAssetMap() {
		ArrayList<ProjectAsset> theProjectAssetList = dbRetrieveProjectAssetList();
		this.projectAssetMap = new HashMap<String, ProjectAsset>();
		for(ProjectAsset theProjectAsset : theProjectAssetList) {
			this.projectAssetMap.put(theProjectAsset.getNodeIdString(), theProjectAsset);
		}
		return this.projectAssetMap.size();
	}
	
	public Collection<ProjectAsset> getProjectAssetCollection() {
		return this.projectAssetMap.values();
	}
	
	public ArrayList<ProjectAsset> getProjectAssetList(String aStrategicMilestoneNodeId) {
		ArrayList<ProjectAsset> theProjectAssetList = new ArrayList<ProjectAsset>();
		for(StrategicCommitment theStrategicCommitment : this.strategicCommitmentMap.values()) {
			if(theStrategicCommitment.getStrategicMilestoneNodeId().equals(aStrategicMilestoneNodeId)) {
				theProjectAssetList.add(getProjectAsset(theStrategicCommitment.getProjectAssetNodeIdString()));
			}
		}
		return theProjectAssetList;
	}
	
	public Collection<ProjectAsset> getProjectAssetCollection(StrategicMilestone aStrategicMilestone) {
		return getProjectAssetList(aStrategicMilestone.getNodeIdString());
	}
	
	public Collection<ProjectAsset> getProjectAssetCollectionSorted(StrategicMilestone aStrategicMilestone) {
		ArrayList<StrategicCommitment> theStrategicCommitmentList = getStrategicCommitmentList(aStrategicMilestone.getNodeIdString());
		Collections.sort(theStrategicCommitmentList);
		ArrayList<ProjectAsset> theProjectAssetList = new ArrayList<ProjectAsset>();
		for(StrategicCommitment theStrategicCommitment : theStrategicCommitmentList) {
			theProjectAssetList.add(getProjectAsset(theStrategicCommitment.getProjectAssetNodeIdString()));
		}
		return theProjectAssetList;
	}
	
	public ProjectAsset getProjectAsset(String aNodeIdString) {
		ProjectAsset theProjectAsset = this.projectAssetMap.get(aNodeIdString);
		if(theProjectAsset == null) {
			theProjectAsset = dbRetrieveProjectAsset(aNodeIdString);
			if(theProjectAsset != null) {
				this.projectAssetMap.put(theProjectAsset.getNodeIdString(), theProjectAsset);
			}
		}
		return theProjectAsset;
	}
	
	public void newProjectAsset(ProjectAsset aProjectAsset) {
		dbInsertProjectAsset(aProjectAsset);
		this.projectAssetMap.put(aProjectAsset.getNodeIdString(), aProjectAsset);
	}

	public void destroyProjectAsset(ProjectAsset aProjectAsset) {
		dbDeleteProjectAsset(aProjectAsset);
		this.projectAssetMap.remove(aProjectAsset.getNodeIdString());
	}
	
			////  Repository Access - PROJECT ASSET

	protected abstract ArrayList<ProjectAsset> dbRetrieveProjectAssetList();

	protected abstract ArrayList<ProjectAsset> dbRetrieveProjectAssetList(StrategicMilestone aStrategicMilestone);
	
	protected abstract ProjectAsset dbRetrieveProjectAsset(String aNodeIdString);
	
	protected abstract void dbInsertProjectAsset(ProjectAsset aProjectAsset);
	
	public abstract void dbDeleteProjectAsset(ProjectAsset aProjectAsset);

	//////  Node - PROJECT ASSET LINK TO WORK PACKAGE  ////////////////////////////////////////////////////////////////////////////////

	protected int initializeProjectAssetLinkToWorkPackageMap() {
		ArrayList<ProjectAssetLinkToWorkPackage> theProjectAssetLinkToWorkPackageList = dbRetrieveProjectAssetLinkToWorkPackageList();
		this.projectAssetLinkToWorkPackageMap = new HashMap<String, ProjectAssetLinkToWorkPackage>();
		for(ProjectAssetLinkToWorkPackage theProjectAssetLinkToWorkPackage : theProjectAssetLinkToWorkPackageList) {
			this.projectAssetLinkToWorkPackageMap.put(theProjectAssetLinkToWorkPackage.getNodeIdString(), theProjectAssetLinkToWorkPackage);
		}
		return this.projectAssetLinkToWorkPackageMap.size();
	}
	
	public Collection<ProjectAssetLinkToWorkPackage> getProjectAssetLinkToWorkPackageCollection() {
		return this.projectAssetLinkToWorkPackageMap.values();
	}
	
	public ArrayList<ProjectAssetLinkToWorkPackage> getProjectAssetLinkToWorkPackageList(String aProjectAssetNodeId) {
	ArrayList<ProjectAssetLinkToWorkPackage> theProjectAssetLinkToWorkPackageList = new ArrayList<ProjectAssetLinkToWorkPackage>();
	for(ProjectAssetLinkToWorkPackage theProjectAssetLinkToWorkPackage : this.projectAssetLinkToWorkPackageMap.values()) {
		if(theProjectAssetLinkToWorkPackage.getParentNodeIdString().equals(aProjectAssetNodeId)) {
			theProjectAssetLinkToWorkPackageList.add(theProjectAssetLinkToWorkPackage);
		}
	}
	return theProjectAssetLinkToWorkPackageList;
}
	
	public Collection<ProjectAssetLinkToWorkPackage> getProjectAssetLinkToWorkPackageCollection(ProjectAsset aProjectAsset) {
		return getProjectAssetLinkToWorkPackageList(aProjectAsset.getNodeIdString());
	}
	
	public ProjectAssetLinkToWorkPackage getProjectAssetLinkToWorkPackage(String aNodeIdString) {
		ProjectAssetLinkToWorkPackage theProjectAssetLinkToWorkPackage = this.projectAssetLinkToWorkPackageMap.get(aNodeIdString);
		if(theProjectAssetLinkToWorkPackage == null) {
			theProjectAssetLinkToWorkPackage = dbRetrieveProjectAssetLinkToWorkPackage(aNodeIdString);
			if(theProjectAssetLinkToWorkPackage != null) {
				this.projectAssetLinkToWorkPackageMap.put(theProjectAssetLinkToWorkPackage.getNodeIdString(), theProjectAssetLinkToWorkPackage);
			}
		}
		return theProjectAssetLinkToWorkPackage;
	}
	
	public void newProjectAssetLinkToWorkPackage(ProjectAssetLinkToWorkPackage aProjectAssetLinkToWorkPackage) {
		dbInsertProjectAssetLinkToWorkPackage(aProjectAssetLinkToWorkPackage);
		this.projectAssetLinkToWorkPackageMap.put(aProjectAssetLinkToWorkPackage.getNodeIdString(), aProjectAssetLinkToWorkPackage);
	}

	public void destroyProjectAssetLinkToWorkPackage(ProjectAssetLinkToWorkPackage aProjectAssetLinkToWorkPackage) {
		dbDeleteProjectAssetLinkToWorkPackage(aProjectAssetLinkToWorkPackage);
		this.projectAssetLinkToWorkPackageMap.remove(aProjectAssetLinkToWorkPackage.getNodeIdString());
	}
	
			////  Repository Access - PROJECT ASSET LINK TO WORK PACKAGE

	protected abstract ArrayList<ProjectAssetLinkToWorkPackage> dbRetrieveProjectAssetLinkToWorkPackageList();

	protected abstract ArrayList<ProjectAssetLinkToWorkPackage> dbRetrieveProjectAssetLinkToWorkPackageList(StrategicMilestone aStrategicMilestone);
	
	protected abstract ProjectAssetLinkToWorkPackage dbRetrieveProjectAssetLinkToWorkPackage(String aNodeIdString);
	
	protected abstract void dbInsertProjectAssetLinkToWorkPackage(ProjectAssetLinkToWorkPackage aProjectAssetLinkToWorkPackage);
	
	public abstract void dbDeleteProjectAssetLinkToWorkPackage(ProjectAssetLinkToWorkPackage aProjectAssetLinkToWorkPackage);

	//////  Node - STRATEGIC COMMITMENT  ////////////////////////////////////////////////////////////////////////////////

	protected int initializeStrategicCommitmentMap() {
		ArrayList<StrategicCommitment> theStrategicCommitmentList = dbRetrieveStrategicCommitmentList();
		this.strategicCommitmentMap = new HashMap<String, StrategicCommitment>();
		for(StrategicCommitment theStrategicCommitment : theStrategicCommitmentList) {
			this.strategicCommitmentMap.put(theStrategicCommitment.getNodeIdString(), theStrategicCommitment);
		}
		return this.strategicCommitmentMap.size();
	}
	
	public Collection<StrategicCommitment> getStrategicCommitmentCollection() {
		return this.strategicCommitmentMap.values();
	}
	
	public ArrayList<StrategicCommitment> getStrategicCommitmentList(String aStrategicMilestoneNodeId) {
		ArrayList<StrategicCommitment> theStrategicCommitmentList = new ArrayList<StrategicCommitment>();
		for(StrategicCommitment theStrategicCommitment : this.strategicCommitmentMap.values()) {
			if(theStrategicCommitment.getStrategicMilestoneNodeId().equals(aStrategicMilestoneNodeId)) {
				theStrategicCommitmentList.add(theStrategicCommitment);
			}
		}
		return theStrategicCommitmentList;
	}
	
	public Collection<StrategicCommitment> getStrategicCommitmentCollection(StrategicCommitment aStrategicCommitment) {
		return getStrategicCommitmentList(aStrategicCommitment.getNodeIdString());
	}
	
	public StrategicCommitment getStrategicCommitment(String aNodeIdString) {
		StrategicCommitment theStrategicCommitment = this.strategicCommitmentMap.get(aNodeIdString);
		if(theStrategicCommitment == null) {
			theStrategicCommitment = dbRetrieveStrategicCommitment(aNodeIdString);
			if(theStrategicCommitment != null) {
				this.strategicCommitmentMap.put(theStrategicCommitment.getNodeIdString(), theStrategicCommitment);
			}
		}
		return theStrategicCommitment;
	}
	
	public void newStrategicCommitment(StrategicCommitment aStrategicCommitment) {
		dbInsertStrategicCommitment(aStrategicCommitment);
		this.strategicCommitmentMap.put(aStrategicCommitment.getNodeIdString(), aStrategicCommitment);
	}

	public void destroyStrategicCommitment(StrategicCommitment aStrategicCommitment) {
		dbDeleteStrategicCommitment(aStrategicCommitment);
		this.strategicCommitmentMap.remove(aStrategicCommitment.getNodeIdString());
	}
	
			////  Repository Access - STRATEGIC COMMITMENT

	protected abstract ArrayList<StrategicCommitment> dbRetrieveStrategicCommitmentList();

	protected abstract ArrayList<StrategicCommitment> dbRetrieveStrategicCommitmentList(FiscalYear aStrategicCommitment);
	
	protected abstract StrategicCommitment dbRetrieveStrategicCommitment(String aNodeIdString);
	
	protected abstract void dbInsertStrategicCommitment(StrategicCommitment aStrategicCommitment);
	
	public abstract void dbDeleteStrategicCommitment(StrategicCommitment aStrategicCommitment);

	
	//////  Node - STRATEGIC MILESTONE  ////////////////////////////////////////////////////////////////////////////////

	protected int initializeStrategicMilestoneMap() {
		ArrayList<StrategicMilestone> theStrategicMilestoneList = dbRetrieveStrategicMilestoneList();
		this.strategicMilestoneMap = new HashMap<String, StrategicMilestone>();
		for(StrategicMilestone theStrategicMilestone : theStrategicMilestoneList) {
			this.strategicMilestoneMap.put(theStrategicMilestone.getNodeIdString(), theStrategicMilestone);
		}
		return this.strategicMilestoneMap.size();
	}
	
	public Collection<StrategicMilestone> getStrategicMilestoneCollection() {
		return this.strategicMilestoneMap.values();
	}
	
	public ArrayList<StrategicMilestone> getStrategicMilestoneList(String aFiscalYearNodeId) {
		ArrayList<StrategicMilestone> theStrategicMilestoneList = new ArrayList<StrategicMilestone>();
		for(StrategicMilestone theStrategicMilestone : this.strategicMilestoneMap.values()) {
			if(theStrategicMilestone.getFiscalYearNodeId().equals(aFiscalYearNodeId)) {
				theStrategicMilestoneList.add(theStrategicMilestone);
			}
		}
		return theStrategicMilestoneList;
	}
	
	public Collection<StrategicMilestone> getStrategicMilestoneCollection(FiscalYear aFiscalYear) {
		return getStrategicMilestoneList(aFiscalYear.getNodeIdString());
	}
	
	public Collection<StrategicMilestone> getStrategicMilestoneCollectionSorted(FiscalYear aFiscalYear) {
		ArrayList<StrategicMilestone> theStrategicMilestoneList = (ArrayList<StrategicMilestone>)getStrategicMilestoneCollection(aFiscalYear);
		Collections.sort(theStrategicMilestoneList);
		return theStrategicMilestoneList;
	}
	
	public StrategicMilestone getStrategicMilestone(String aNodeIdString) {
		StrategicMilestone theStrategicMilestone = this.strategicMilestoneMap.get(aNodeIdString);
		if(theStrategicMilestone == null) {
			theStrategicMilestone = dbRetrieveStrategicMilestone(aNodeIdString);
			if(theStrategicMilestone != null) {
				this.strategicMilestoneMap.put(theStrategicMilestone.getNodeIdString(), theStrategicMilestone);
			}
		}
		return theStrategicMilestone;
	}
	
	public void newStrategicMilestone(StrategicMilestone aStrategicMilestone) {
		dbInsertStrategicMilestone(aStrategicMilestone);
		this.strategicMilestoneMap.put(aStrategicMilestone.getNodeIdString(), aStrategicMilestone);
	}

	public void destroyStrategicMilestone(StrategicMilestone aStrategicMilestone) {
		dbDeleteStrategicMilestone(aStrategicMilestone);
		this.strategicMilestoneMap.remove(aStrategicMilestone.getNodeIdString());
	}
	
			////  Repository Access - STRATEGIC MILESTONE

	protected abstract ArrayList<StrategicMilestone> dbRetrieveStrategicMilestoneList();

	protected abstract ArrayList<StrategicMilestone> dbRetrieveStrategicMilestoneList(FiscalYear aFiscalYear);
	
	protected abstract StrategicMilestone dbRetrieveStrategicMilestone(String aNodeIdString);
	
	protected abstract void dbInsertStrategicMilestone(StrategicMilestone aStrategicMilestone);
	
	public abstract void dbDeleteStrategicMilestone(StrategicMilestone aStrategicMilestone);

	
	//////  Node - WORK PACKAGE  ////////////////////////////////////////////////////////////////////////////////

	protected int initializeWorkPackageMap() {
		ArrayList<WorkPackage> theWorkPackageList = dbRetrieveWorkPackageList();
		this.workPackageMap = new HashMap<String, WorkPackage>();
		for(WorkPackage theWorkPackage : theWorkPackageList) {
			this.workPackageMap.put(theWorkPackage.getNodeIdString(), theWorkPackage);
		}
		return this.workPackageMap.size();
	}
	
	public Collection<WorkPackage> getWorkPackageCollection() {
		return this.workPackageMap.values();
	}
	
	public ArrayList<WorkPackage> getWorkPackageListForProjectAsset(String aProjectAssetNodeId) {
		ArrayList<WorkPackage> theWorkPackageList = new ArrayList<WorkPackage>();
		for(ProjectAssetLinkToWorkPackage theProjectAssetLinkToWorkPackage : this.projectAssetLinkToWorkPackageMap.values()) {
			if(theProjectAssetLinkToWorkPackage.getProjectAssetNodeId().equals(aProjectAssetNodeId)) {
				theWorkPackageList.add(
						FmmDatabaseMediator.getActiveMediator().getWorkPackage(
								theProjectAssetLinkToWorkPackage.getWorkPackageNodeId() ) );
			}
		}
		return theWorkPackageList;
	}
	
	public Collection<WorkPackage> getWorkPackageCollectionForProjectAsset(ProjectAsset aProjectAsset) {
		return getWorkPackageListForProjectAsset(aProjectAsset.getNodeIdString());
	}
	
	public Collection<WorkPackage> getWorkPackageCollectionForProjectAssetSorted(ProjectAsset aProjectAsset) {
		// TODO - this needs to sort based on the sequence in ProjectAssetLinkToWorkPackage   SDS
		ArrayList<WorkPackage> theWorkPackageList = (ArrayList<WorkPackage>)getWorkPackageCollectionForProjectAsset(aProjectAsset);
		Collections.sort(theWorkPackageList);
		return theWorkPackageList;
	}
	
	public WorkPackage getWorkPackage(String aNodeIdString) {
		WorkPackage theWorkPackage = this.workPackageMap.get(aNodeIdString);
		if(theWorkPackage == null) {
			theWorkPackage = dbRetrieveWorkPackage(aNodeIdString);
			if(theWorkPackage != null) {
				this.workPackageMap.put(theWorkPackage.getNodeIdString(), theWorkPackage);
			}
		}
		return theWorkPackage;
	}
	
	public void newWorkPackage(WorkPackage aWorkPackage) {
		dbInsertWorkPackage(aWorkPackage);
		this.workPackageMap.put(aWorkPackage.getNodeIdString(), aWorkPackage);
	}

	public void destroyWorkPackage(WorkPackage aWorkPackage) {
		dbDeleteWorkPackage(aWorkPackage);
		this.workPackageMap.remove(aWorkPackage.getNodeIdString());
	}
	
			////  Repository Access - WORK PACKAGE

	protected abstract ArrayList<WorkPackage> dbRetrieveWorkPackageList();

	protected abstract ArrayList<WorkPackage> dbRetrieveWorkPackageList(FiscalYear aFiscalYear);
	
	protected abstract WorkPackage dbRetrieveWorkPackage(String aNodeIdString);
	
	protected abstract void dbInsertWorkPackage(WorkPackage aWorkPackage);
	
	public abstract void dbDeleteWorkPackage(WorkPackage aWorkPackage);

	public FmmNodeInfo getFmmNodeSummary(String aNodeIdString) {
		FmmNodeDictionary theDictionaryEntry = FmmNodeDictionary.getEntryForNodeIdString(aNodeIdString);
		switch(theDictionaryEntry) {
			case FISCAL_YEAR:
				return getFiscalYear(aNodeIdString);
			case STRATEGIC_MILESTONE:
				break;
			case PROJECT_ASSET:
				break;
			default:
		}
		return null;
	}

	/////////////////////
	/////////////////////
	/////////////////////

	
	//////  Node - FSE DOCUMENT  ////////////////////////////////////////////////////////////////////////////////

	protected int initializeFseDocumentMap() {
		ArrayList<FseDocument> theFseDocumentList = dbRetrieveFseDocumentList();
		this.fseDocumentMap.clear();
		for(FseDocument theFseDocument : theFseDocumentList) {
			this.fseDocumentMap.put(theFseDocument.getDocumentId(), theFseDocument);
		}
		return this.fseDocumentMap.size();
	}
	
	public Collection<FseDocument> getFseDocumentCollection() {
		return this.fseDocumentMap.values();
	}
	
	public FseDocument getFseDocument(String aDocumentId) {
		FseDocument theFseDocument = this.fseDocumentMap.get(aDocumentId);
		if(theFseDocument == null) {
			theFseDocument = dbRetrieveFseDocument(aDocumentId);
			if(theFseDocument != null) {
				this.fseDocumentMap.put(theFseDocument.getNodeIdString(), theFseDocument);
			}
		}
		return theFseDocument;
	}

	public FseDocument getFseDocumentForParent(String aParentNodeIdString) {
		FseDocument theDocumentForParent = null;
		for(FseDocument theFseDocument : this.fseDocumentMap.values()) {
			if(theFseDocument.getDocumentId() == aParentNodeIdString) {
				theDocumentForParent =  theFseDocument;
			}
		}
		if(theDocumentForParent == null) {
			theDocumentForParent = dbRetrieveFseDocumentForParent(aParentNodeIdString);
			if(theDocumentForParent != null) {
				this.fseDocumentMap.put(theDocumentForParent.getDocumentId(), theDocumentForParent);
			}
		}
		return theDocumentForParent;
	}

	public FseDocument getFseDocumentForParentOrCreate(String aParentNodeIdString) {
		FseDocument theDocumentForParent = getFseDocumentForParent(aParentNodeIdString);
		if(theDocumentForParent == null) {
			theDocumentForParent = new FseDocument(aParentNodeIdString, false);
			newFseDocument(theDocumentForParent);
		}
		return theDocumentForParent;
	}
	
	public void newFseDocument(FseDocument anFseDocument) {
		dbInsertFseDocumentTransaction(anFseDocument);
		this.fseDocumentMap.put(anFseDocument.getNodeIdString(), anFseDocument);
	}

	public void destroyFseDocument(FseDocument anFseDocument) {
		dbDeleteFseDocument(anFseDocument);
		this.fseDocumentMap.remove(anFseDocument.getDocumentId());
	}
	
			////  Repository Access - FSE DOCUMENT

	protected abstract ArrayList<FseDocument> dbRetrieveFseDocumentList();

	protected abstract FseDocument dbRetrieveFseDocument(String aDocumentId);
	
	protected abstract FseDocument dbRetrieveFseDocumentForParent(String aNodeIdString);
	
	protected abstract void dbInsertFseDocument(FseDocument anFseDocument);
	
	public abstract void dbDeleteFseDocument(FseDocument anFseDocument);

	protected abstract void dbInsertFseDocumentTransaction(FseDocument anFseDocument);

	/////////////////////
	/////////////////////
	/////////////////////
	
}
